#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/cdev.h>

#define CHAR_DEV_MAJOR 256
#define CHAR_DEV_MINOR 0
#define CHAR_DEV_CNT 1
#define CHAR_DEV_NAME "char-dev-driver"

// 静态定义字符设备，可通过 struct cdev *cdev_alloc(void); 动态申请
static struct cdev chrdev;

// 用来定义操作字符设备的方法
static struct file_operations chrdev_ops = {
    .owner = THIS_MODULE,
};

static int __init char_dev_driver_init(void)
{
    int ret;
    dev_t dev;

    //合成设备号
    dev = MKDEV(CHAR_DEV_MAJOR, CHAR_DEV_MINOR);
    //注册设备号
    ret = register_chrdev_region(dev, CHAR_DEV_CNT, CHAR_DEV_NAME);
    if (ret)
        goto reg_err;

    //初始化字符设备
    cdev_init(&chrdev, &chrdev_ops);
    chrdev.owner = THIS_MODULE;

    //将主设备号对255取余添加到cdev_map中
    ret = cdev_add(&chrdev, dev, CHAR_DEV_CNT);
    if (ret)
        goto add_err;

    return 0;
add_err:
    unregister_chrdev_region(dev, CHAR_DEV_CNT);
reg_err:
    return ret;
}

static void __exit char_dev_driver_exit(void)
{
    dev_t dev;

    //合成设备号
    dev = MKDEV(CHAR_DEV_MAJOR, CHAR_DEV_MINOR);

    //删除cdev
    cdev_del(&chrdev);

    //注销设备号
    unregister_chrdev_region(dev, CHAR_DEV_CNT);
}

module_init(char_dev_driver_init);
module_exit(char_dev_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Biven Tang <bivent@163.com>");
MODULE_DESCRIPTION("char device driver!");
MODULE_ALIAS("char-dev-driver");
